package cn.yangliu.nacos.oauth2.config;

import java.io.IOException;
import java.util.Objects;

import javax.servlet.http.HttpServletResponse;

import cn.yangliu.nacos.comm.enums.GlobalResultCode;
import cn.yangliu.nacos.comm.tools.WebUtils;
import cn.yangliu.nacos.oauth2.ex.OAuthException;
import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.databind.SerializerProvider;
import com.fasterxml.jackson.databind.ser.std.StdSerializer;
import org.springframework.http.HttpStatus;
import org.springframework.security.oauth2.client.resource.OAuth2AccessDeniedException;
import org.springframework.security.oauth2.common.exceptions.BadClientCredentialsException;
import org.springframework.security.oauth2.common.exceptions.InsufficientScopeException;
import org.springframework.security.oauth2.common.exceptions.InvalidClientException;
import org.springframework.security.oauth2.common.exceptions.InvalidGrantException;
import org.springframework.security.oauth2.common.exceptions.InvalidRequestException;
import org.springframework.security.oauth2.common.exceptions.InvalidScopeException;
import org.springframework.security.oauth2.common.exceptions.InvalidTokenException;
import org.springframework.security.oauth2.common.exceptions.RedirectMismatchException;
import org.springframework.security.oauth2.common.exceptions.UnauthorizedClientException;
import org.springframework.security.oauth2.common.exceptions.UnauthorizedUserException;
import org.springframework.security.oauth2.common.exceptions.UnsupportedGrantTypeException;
import org.springframework.security.oauth2.common.exceptions.UnsupportedResponseTypeException;
import org.springframework.security.oauth2.common.exceptions.UserDeniedAuthorizationException;
import org.springframework.stereotype.Component;

/**
 * The interface Oauth 2 exception serializer.
 *
 * @author 问道于盲
 */
@Component
public class Oauth2ExceptionSerializer
        extends StdSerializer<OAuthException> {

    /**
     * serial number.
     */
    private static final long serialVersionUID = 6049492909669907080L;

    /**
     * Constructor.
     */
    public Oauth2ExceptionSerializer() {
        super(OAuthException.class);
    }

    /**
     * Custom serialize method.
     *
     * @param value    the value
     * @param gen      the gen
     * @param provider the provider
     * @throws IOException Signals that an I/O exception has occurred.
     */
    @Override
    public void serialize(OAuthException value, JsonGenerator gen,
                          SerializerProvider provider) throws IOException {
        gen.writeStartObject();
        int code = 0;
        String msg = "";
        int statusCode = value.getHttpErrorCode();
        /**
         * 1.异常为BadClientCredentialsException时设置INVALID_CLIENT的code,msg
         */
        if (value.getCause() instanceof BadClientCredentialsException
                || value.getCause() instanceof InvalidClientException) {
            code = GlobalResultCode.INVALID_CLIENT.getCode();
            msg = GlobalResultCode.INVALID_CLIENT.getMsg();
        } else if (value.getCause() instanceof InvalidGrantException
                || value.getCause() instanceof RedirectMismatchException) {
            /**
             * 2.异常为InvalidRequestException时设置INVALID_GRANT的code,msg
             */
            code = GlobalResultCode.INVALID_GRANT.getCode();
            msg = GlobalResultCode.INVALID_GRANT.getMsg();
        } else if (value.getCause() instanceof InvalidRequestException) {
            /**
             * 3.异常为InvalidRequestException时设置BAD_REQUEST的code,msg
             */
            code = GlobalResultCode.BAD_REQUEST.getCode();
            msg = GlobalResultCode.BAD_REQUEST.getMsg();
        } else if (value.getCause() instanceof InvalidTokenException) {
            /**
             * 4.异常为InvalidTokenException时设置ACCESS_TOKEN_INVALID的code,msg
             */
            code = GlobalResultCode.ACCESS_TOKEN_INVALID.getCode();
            msg = GlobalResultCode.ACCESS_TOKEN_INVALID.getMsg();
        } else if (value.getCause() instanceof UnauthorizedClientException) {
            /**
             * 5.异常为UnauthorizedClientException时设置UNAUTHORIZED_CLIENT的code,msg
             */
            code = GlobalResultCode.UNAUTHORIZED_CLIENT.getCode();
            msg = GlobalResultCode.UNAUTHORIZED_CLIENT.getMsg();
        } else if (value.getCause() instanceof InsufficientScopeException
                || value.getCause() instanceof InvalidScopeException) {
            /**
             * 6.异常为InsufficientScopeException或者InvalidScopeException时设置INSUFFICIENT_SCOPE的code,msg
             */
            code = GlobalResultCode.INSUFFICIENT_SCOPE.getCode();
            msg = GlobalResultCode.INSUFFICIENT_SCOPE.getMsg();
        } else if (value.getCause() instanceof OAuth2AccessDeniedException
                || value.getCause() instanceof UserDeniedAuthorizationException) {
            /**
             * 7.异常为OAuth2AccessDeniedException或者UserDeniedAuthorizationException时设置ACCESS_DENIED的code,msg
             */
            code = GlobalResultCode.ACCESS_DENIED.getCode();
            msg = GlobalResultCode.ACCESS_DENIED.getMsg();
        } else if (value.getCause() instanceof UnauthorizedUserException) {
            /**
             * 8.异常为UnauthorizedUserException时设置UNAUTHORIZED_USER的code,msg
             */
            code = GlobalResultCode.UNAUTHORIZED_USER.getCode();
            msg = GlobalResultCode.UNAUTHORIZED_USER.getMsg();
        } else if (value
                .getCause() instanceof UnsupportedResponseTypeException) {
            /**
             * 9.异常为UnsupportedResponseTypeException时设置UNSUPPORTED_RESPONSE_TYPE的code,msg
             */
            code = GlobalResultCode.UNSUPPORTED_RESPONSE_TYPE.getCode();
            msg = GlobalResultCode.UNSUPPORTED_RESPONSE_TYPE.getMsg();
        } else if (value.getCause() instanceof UnsupportedGrantTypeException) {
            /**
             * 10.异常为UnsupportedGrantTypeException时设置UNSUPPORTED_GRANT_TYPE的code,msg
             */
            code = GlobalResultCode.UNSUPPORTED_GRANT_TYPE.getCode();
            msg = GlobalResultCode.UNSUPPORTED_GRANT_TYPE.getMsg();
        } else if (statusCode == HttpStatus.FORBIDDEN.value()) {
            /**
             * 11.异常为FORBIDDEN时设置INSUFFICIENT_AUTHENTICATION的code,msg
             */
            code = GlobalResultCode.INSUFFICIENT_AUTHENTICATION.getCode();
            msg = GlobalResultCode.INSUFFICIENT_AUTHENTICATION.getMsg();
        } else if (statusCode == HttpStatus.METHOD_NOT_ALLOWED.value()) {
            /**
             * 12.异常为METHOD_NOT_ALLOWED时设置METHOD_NOT_ALLOWED的code,msg
             */
            code = GlobalResultCode.METHOD_NOT_ALLOWED.getCode();
            msg = GlobalResultCode.METHOD_NOT_ALLOWED.getMsg();
        } else if (statusCode == HttpStatus.UNAUTHORIZED.value()) {
            /**
             * 13.异常为UNAUTHORIZED时设置UNAUTHORIZED的code,msg
             */
            code = GlobalResultCode.UNAUTHORIZED.getCode();
            msg = GlobalResultCode.UNAUTHORIZED.getMsg();
        } else {
            /**
             * 14.设置SYSTEM_INNER_ERROR的code,msg
             */
            msg = GlobalResultCode.SYSTEM_INNER_ERROR.getMsg().concat(",")
                    .concat(String.valueOf(code)).concat(",").concat(msg);
            code = GlobalResultCode.SYSTEM_INNER_ERROR.getCode();
        }
        gen.writeNumberField("code", code);
        gen.writeStringField("msg", msg + "," + value.getMessage());
        HttpServletResponse response  = WebUtils.getResponse();
        if (Objects.nonNull(response)) {
            response.setStatus(code);
        }
        gen.writeEndObject();
    }
}
